﻿using System;
using System.Collections.Generic; 
using System.Windows.Forms;
using System.Diagnostics; 
using System.Threading;
using Newtonsoft.Json;
using System.IO;
using System.Drawing.Printing;
using System.Net;
using System.Net.Sockets;
using Microsoft.Win32;
using Seagull.BarTender.Print;
using System.Runtime.InteropServices;
using System.Drawing;
using log4net;
using System.Collections.Concurrent;
using System.Reflection;

/**
 * C# 使用 BarTender 条码标签打印处理
 **/

namespace PrintLabel
{
    public partial class Main : Form
    {
        private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        private static ConcurrentQueue<PrintData> queue = new ConcurrentQueue<PrintData>();

        private HttpService httpService = new HttpService();

        private static Thread printThread;

        private Engine engine = null;

        public static PrintDocument fPrintDocument = new PrintDocument();
        public Main()
        {
            try
            {
                Process currentProcess = Process.GetCurrentProcess();
                string processName = currentProcess.ProcessName;
                Process[] processArray = Process.GetProcessesByName(processName);
                bool flag = processArray != null && processArray.Length > 1;
                if (flag)
                {
                    MessageBox.Show("相同的进程不可重复打开！", "提示", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                    base.Close();
                    return;
                }
            }
            catch (Exception ex)
            {
            }
            this.InitializeComponent();
            base.WindowState = FormWindowState.Minimized;
            base.ShowInTaskbar = false;
            Control.CheckForIllegalCrossThreadCalls = false;
        }


        private void Main_Load(object sender, EventArgs e)
        {
            try
            {
                this.engine = new Engine(true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, "请安装BarTender11，详细信息："+ex.Message, "打印程序");
                base.Dispose();
                base.Close();
                Environment.Exit(0);

            }
            this.StartUp(true);
            try
            {
                ThreadStart thStart = new ThreadStart(this.start);
                new Thread(thStart)
                {
                    Priority = ThreadPriority.Highest,
                    IsBackground = true
                }.Start();
                List<string> printNames = this.GetLocalPrinters();
                this.labIp.Text = Main.GetLocalIp() + ":10101";
                this.GetLocalPrintersData();
            }
            catch (Exception)
            {
            }

            this.execPrintThread();
        }

        private void SetNamedSubStringValue(LabelFormatDocument btFormat, Dictionary<string, string> dict, string routingKey)
        {
            foreach (SubString namedSubStrings in btFormat.SubStrings)
            {
                bool flag = dict.ContainsKey(namedSubStrings.Name);
                if (flag)
                {
                    namedSubStrings.Value = dict[namedSubStrings.Name];
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            List<Dictionary<string, string>> keyvalues = new List<Dictionary<string, string>>();
            bool flag = this.txtLabel.Text != null && this.txtLabel.Text != "";
            if (flag)
            {
                keyvalues.Add(new Dictionary<string, string>
                {
                    {
                        "no",
                        this.txtLabel.Text
                    }
                });
                string message = "未知错误";
                bool printStatus = this.Print2(keyvalues, "/test.btw", out message, this.comPrintNames.SelectedItem.ToString(), this.comboBox1.SelectedIndex + 1, true);
                bool flag2 = printStatus;
                if (flag2)
                {
                    MessageBox.Show(message);
                }
                else
                {
                    MessageBox.Show(message);
                }
            }
            else
            {
                MessageBox.Show("打印数据不能为空");
            }
        }

        private void Main_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            base.WindowState = FormWindowState.Minimized;
            base.ShowInTaskbar = false;
            this.notifyIcon1.ShowBalloonTip(2000, "最小化到托盘", "程序已经缩小到托盘，单击打开程序。", ToolTipIcon.Info);
        }

        private void toolStripMenuItem1_Click(object sender, EventArgs e)
        {
            base.Dispose();
            base.Close();
            Environment.Exit(0);
        }

        private void 显示ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            base.WindowState = FormWindowState.Normal;
        }


        public bool printShow(List<Dictionary<string, string>> keyvaluess, string routingKey, out string message)
        {
            Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：1.接收到预览请求");
            LabelFormatDocument btFormat = null;
            Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：2.下载模板文件");
            string[] routingKeyArr = routingKey.Split(new char[]
            {
                '/'
            });
            DownloadClass dd = new DownloadClass();
            dd.StrUrl = routingKey;
            bool flag = !Directory.Exists(Application.StartupPath + "\\Formats\\");
            if (flag)
            {
                Directory.CreateDirectory(Application.StartupPath + "\\Formats\\");
            }
            string localurl = dd.StrFileName = Application.StartupPath + "\\Formats\\" + routingKeyArr[routingKeyArr.Length - 1];
            bool flag2 = !File.Exists(localurl);
            if (flag2)
            {
                dd.DownloadFile(localurl);
            }
            bool result;
            lock (this.engine)
            {
                Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：3.1app");
                try
                {
                    btFormat = this.engine.Documents.Open(localurl);
                }
                catch (COMException comException)
                {
                    File.Delete(localurl);
                    message = string.Format("Unable to open format: {0}\nReason: {1}", localurl, comException.Message);
                    return false;
                }
                Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：4.2app");
                List<string> imgs = new List<string>();
                foreach (Dictionary<string, string> keyvalues in keyvaluess)
                {
                    try
                    {
                        this.SetNamedSubStringValue(btFormat, keyvalues, routingKey);
                    }
                    catch (Exception e)
                    {
                        message = "模板数据填充失败：" + e.Message;
                        return false;
                    }
                    try
                    {
                        Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：5.填充模板数据完成");
                        string uuid = Guid.NewGuid().ToString();
                        Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：6.开始预览");
                        btFormat.ExportImageToFile(Application.StartupPath + "\\" + uuid + ".png", ImageType.JPEG, Seagull.BarTender.Print.ColorDepth.ColorDepth256, new Resolution(180), OverwriteOptions.DoNotOverwrite);
                        Main.log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：7.预览图片生成成功");
                        Image image = Image.FromFile(Application.StartupPath + "\\" + uuid + ".png");
                        string imgBase = BitmapOper.ImageToBase64(image);
                        image.Dispose();
                        File.Delete(Application.StartupPath + "\\" + uuid + ".png");
                        imgs.Add("data:image/png;base64," + imgBase);
                        log.Info(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "：8.预览图片返回成功");
                    }
                    catch (Exception e2)
                    {
                        btFormat.Close(SaveOptions.DoNotSaveChanges);
                        message = "预览失败：" + e2.Message;
                        return false;
                    }
                }
                btFormat.Close(SaveOptions.DoNotSaveChanges);
                message = JsonConvert.SerializeObject(imgs);
                result = true;
            }
            return result;
        }




        public bool Print2(List<Dictionary<string, string>> keyvalues, string routingKey, out string message, string printerName, int printNum,bool isLocal = false)
        {
            List<string> printName = this.GetLocalPrinters();
            bool flag = !printName.Contains(printerName);
            bool result;
            if (flag)
            {
                message = "【" + printerName + "】该打印机未配置";
                result = false;
            }
            else
            {
                string[] routingKeyArr = routingKey.Split(new char[]
                {
                    '/'
                });
                DownloadClass dd = new DownloadClass();
                dd.StrUrl = routingKey;
                bool flag2 = !Directory.Exists(Application.StartupPath + "\\Formats\\");
                if (flag2)
                {
                    Directory.CreateDirectory(Application.StartupPath + "\\Formats\\");
                }
                string localurl = dd.StrFileName = Application.StartupPath + "\\Formats\\" + routingKeyArr[routingKeyArr.Length - 1];
                bool flag3 = !File.Exists(localurl);
                if (flag3)
                {
                    dd.DownloadFile(localurl);
                }
                PrintData printData = new PrintData(localurl, printerName, routingKey, (printNum < 1) ? 1 : printNum, keyvalues);
                if (isLocal) {
                    result = localPrint(printData,out message);
                } else {
                    Main.queue.Enqueue(printData);
                    message = "打印成功";
                    result = true;
                }
            }
            return result;
        }

        bool localPrint(PrintData printData,out String message)
        {
            Engine obj = this.engine;
            lock (obj)
            {
                LabelFormatDocument btFormat = null;
                try
                {
                    btFormat = this.engine.Documents.Open(printData.localurl);
                }
                catch (Exception comException)
                {
                    message = "加载模板出错：" + string.Format("Unable to open format: {0}\nReason: {1}", printData.localurl, comException.Message);
                    return false;
                }
                try
                {
                    bool flag3 = btFormat.PrintSetup.PrinterName != "" && btFormat.PrintSetup.PrinterName != null;
                    if (flag3)
                    {
                        btFormat.PrintSetup.PrinterName = printData.printerName;
                    }
                    btFormat.PrintSetup.IdenticalCopiesOfLabel = printData.printNum;
                    btFormat.PrintSetup.NumberOfSerializedLabels = 1;
                    Dictionary<string, string> dict = printData.keyvalues[0];

                    this.SetNamedSubStringValue(btFormat, dict, printData.routingKey);
                    int waitForCompletionTimeout = 1000;
                    Messages messages;
                    Seagull.BarTender.Print.Result result = btFormat.Print("自动打印软件", waitForCompletionTimeout, out messages);
                    bool flag4 = result == Seagull.BarTender.Print.Result.Success;
                    if (flag4)
                    {
                        message = string.Concat(new string[]
                        {
                                        "打印机-",
                                        printData.printerName,
                                        "，打印成功:(",
                                        printData.routingKey,
                                        ")",
                                        JsonConvert.SerializeObject(dict)
                        });
                        return true;
                    }
                    else
                    {
                        string messageString = "\n\nMessages:";
                        foreach (Seagull.BarTender.Print.Message message2 in messages)
                        {
                            messageString = messageString + "\n\n" + message2.Text;
                        }
                        message = string.Concat(new string[]
                        {
                                        "打印机-",
                                        printData.printerName,
                                        "，打印失败:(",
                                        printData.routingKey,
                                        ")",
                                        JsonConvert.SerializeObject(dict)
                        });
                        return false;
                    }
                }
                catch (Exception e)
                {
                    message = string.Concat(new string[]
                   {
                                "打印机-",
                                printData.printerName,
                                "，打印出错:(",
                                printData.routingKey,
                                ")",
                                e.Message
                   });
                    return false;
                }
            }
        }

        public void execPrintThread()
        {
            bool flag2 = Main.printThread == null || !Main.printThread.IsAlive;
            if (flag2)
            {
                Main.printThread = new Thread(new ThreadStart(this.execPrint));
                Main.printThread.Start();
            }
        }

        private void execPrint()
        {
            for (; ; )
            {
                try
                {
                    this.label5.Text = "队列中剩余【" + Main.queue.Count.ToString() + "】条打印消息";
                    PrintData printData = new PrintData();
                    bool isData = Main.queue.TryDequeue(out printData);
                    bool flag = isData;
                    if (flag)
                    {
                        Engine obj = this.engine;
                        lock (obj)
                        {
                            LabelFormatDocument btFormat = null;
                            try
                            {
                                btFormat = this.engine.Documents.Open(printData.localurl);
                            }
                            catch (Exception comException)
                            {
                                string message = string.Format("Unable to open format: {0}\nReason: {1}", printData.localurl, comException.Message);
                                Main.log.Error("加载模板出错：" + message);
                                continue;
                            }
                            try
                            {
                                bool flag3 = btFormat.PrintSetup.PrinterName != "" && btFormat.PrintSetup.PrinterName != null;
                                if (flag3)
                                {
                                    btFormat.PrintSetup.PrinterName = printData.printerName;
                                }
                                btFormat.PrintSetup.IdenticalCopiesOfLabel = printData.printNum;
                              btFormat.PrintSetup.NumberOfSerializedLabels = 1;
                                foreach (Dictionary<string, string> dict in printData.keyvalues)
                                {
                                    this.SetNamedSubStringValue(btFormat, dict, printData.routingKey);
                                    int waitForCompletionTimeout = 1000;
                                    Messages messages;
                                    Seagull.BarTender.Print.Result result = btFormat.Print("自动打印软件", waitForCompletionTimeout, out messages);
                                    bool flag4 = result == Seagull.BarTender.Print.Result.Success;
                                    if (flag4)
                                    {
                                        Main.log.Info(string.Concat(new string[]
                                        {
                                        "打印机-",
                                        printData.printerName,
                                        "，打印成功:(",
                                        printData.routingKey,
                                        ")",
                                        JsonConvert.SerializeObject(dict)
                                        }));
                                    }
                                    else
                                    {
                                        string messageString = "\n\nMessages:";
                                        foreach (Seagull.BarTender.Print.Message message2 in messages)
                                        {
                                            messageString = messageString + "\n\n" + message2.Text;
                                        }
                                        Main.log.Info(string.Concat(new string[]
                                        {
                                        "打印机-",
                                        printData.printerName,
                                        "，打印失败:(",
                                        printData.routingKey,
                                        ")",
                                        JsonConvert.SerializeObject(dict)
                                        }));
                                    }
                                }
                                continue;
                            }
                            catch (Exception e)
                            {
                                string message = string.Concat(new string[]
                                {
                                "打印机-",
                                printData.printerName,
                                "，打印出错:(",
                                printData.routingKey,
                                ")",
                                e.Message
                                });
                                Main.log.Error(message);
                                continue;
                            }
                        }
                    }
                    bool flag5 = Main.queue.Count > 0;
                    if (flag5)
                    {
                        Main.log.Error("队列中有" + Main.queue.Count.ToString() + "数据，取不出来");
                    }
                    Thread.Sleep(5000);
                }
                catch (Exception e) {
                    log.Error("线程内打印出错：" + e.Message);
                }
            }
        }

        public static string GetLocalIp()
        {
            string ip = "1.1.1.1";
            string result;
            try
            {
                string HostName = Dns.GetHostName();
                IPHostEntry IpEntry = Dns.GetHostEntry(HostName);
                for (int i = 0; i < IpEntry.AddressList.Length; i++)
                {
                    bool flag = IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork;
                    if (flag)
                    {
                        ip = IpEntry.AddressList[i].ToString();
                        return ip;
                    }
                }
                result = ip;
            }
            catch (Exception ex)
            {
                MessageBox.Show("获取本机IP出错:" + ex.Message);
                result = ip;
            }
            return result;
        }

        public void StartUp(bool isAutoRun = true)
        {
            try
            {
                string path = Application.ExecutablePath;
                RegistryKey rk = Registry.LocalMachine;
                RegistryKey rk2 = rk.CreateSubKey("Software\\Microsoft\\Windows\\CurrentVersion\\Run");
                if (isAutoRun)
                {
                    rk2.SetValue("PrintLabel", path);
                }
                else
                {
                    rk2.DeleteValue("PrintLabel", false);
                }
                rk2.Close();
                rk.Close();
                if (isAutoRun)
                {
                    this.notifyIcon1.ShowBalloonTip(1000, "通知", "自动打印程序已开启开机自启", ToolTipIcon.Info);
                }
            }
            catch
            {
                this.notifyIcon1.ShowBalloonTip(3000, "通知", "开机自动启动服务注册被拒绝!请确认有系统管理员权限!", ToolTipIcon.Info);
            }
        }


        public void start()
        {
            this.httpService.open(this);
        }

        public string DefaultPrinter
        {
            get
            {
                return Main.fPrintDocument.PrinterSettings.PrinterName;
            }
        }

        public List<string> GetLocalPrinters()
        {
            List<string> fPrinters = new List<string>();
            fPrinters.Add(this.DefaultPrinter);
            foreach (object obj in PrinterSettings.InstalledPrinters)
            {
                string fPrinterName = (string)obj;
                bool flag = !fPrinters.Contains(fPrinterName);
                if (flag)
                {
                    fPrinters.Add(fPrinterName);
                }
            }
            return fPrinters;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.GetLocalPrintersData();
        }

        public void GetLocalPrintersData()
        {
            this.comPrintNames.Items.Clear();
            foreach (object obj in PrinterSettings.InstalledPrinters)
            {
                string fPrinterName = (string)obj;
                this.comPrintNames.Items.Add(fPrinterName);
            }
            this.comPrintNames.SelectedIndex = 0;
            this.comboBox1.SelectedIndex = 0;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            this.GetLocalPrintersData();
        }

        private void button3_Click_1(object sender, EventArgs e)
        {
            Clipboard.SetDataObject(this.comPrintNames.SelectedItem);
            MessageBox.Show("复制成功");
        }
    }
}
